/*
@STI LICENSE
(C) 2006-2008 Universit�t Innsbruck.

This file is part of myOntology.

myOntologyis free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

myOntologyis distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with myOntology.  If not, see <http://www.gnu.org/licenses/>.

@STI LICENSE */
/**
 * 
 */
package org.myontology.controller;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import model.Vocabulary;

import org.apache.log4j.Logger;
import org.myontology.model.Property;
import org.myontology.model.Subject;
import org.myontology.model.Type;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.query.BindingSet;
import org.openrdf.query.QueryLanguage;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;

import controller.sesameDataConnector.AbstractDataConnector;

/**
 * @author <a href="michael.hackl@sti2.at">Michael Hackl</a>
 * Project: Myontology - www.myontology.org
 * STI
 *
 */
public class SesameSession implements LifeCycle{

	private RepositoryConnection connection;
	private static Logger logger = Logger.getLogger(SesameSession.class);
	
	public void add(URI s,URI p,Value o) throws Exception{
		connection.add(s, p,o);
	}
	
	public void update(URI s,URI p,Value o) throws Exception{

		connection.remove(s, p,null);
		if (o!=null)
			connection.add(s, p,o);
	}
	
	public void remove(URI s,URI p,Value o) throws Exception{
		connection.remove(s, p,o);
	}
	
	public List<String> loadSubjectsByObject(URI p,Value o) throws Exception {
		RepositoryResult<Statement> statements=null;
		List<String> result = new ArrayList<String>();
		try {
			statements = connection.getStatements(null, p, o, false);
			while (statements.hasNext()){
				Statement st = statements.next();
				result.add(st.getSubject().stringValue());
			}
		} catch (Exception e) {
			throw e;
		}
		finally {
			if (statements!=null)
				statements.close();
		}
		return result;
	}
	
	public String loadSingleObject(URI s,URI p) throws Exception{
		RepositoryResult<Statement> statements=null;
		String result = null;
		try {
			statements = connection.getStatements(s, p, null, false);
			if (statements.hasNext()){
				Statement st = statements.next();
				result = st.getObject().stringValue();
			}
		} catch (Exception e) {
			throw e;
		}
		finally {
			if (statements!=null)
				statements.close();
		}
		return result;
	}
	
	public boolean hasTriple(URI s,URI p,Value o) throws Exception{
		RepositoryResult<Statement> statements=null;
		boolean result = false;
		try {
			statements = connection.getStatements(s, p, o, false);
			if (statements.hasNext())
				result = true;
		} catch (Exception e) {
			throw e;
		}
		finally {
			if (statements!=null)
				statements.close();
		}
		return result;
	}
	
	public void executeQuery(String query,ResultSetHandler handler) throws Exception {
		TupleQueryResult result=null;
		try {
			TupleQuery tupleQuery = connection.prepareTupleQuery(QueryLanguage.SERQL, query);
			result = tupleQuery.evaluate();
			while (result.hasNext()) {
				BindingSet set = result.next();
				handler.handleBindingSet(set);
			}
		}
		catch (Exception e) {
			throw e;
		}
		finally {
			if (result!=null)
				result.close();
		}
	}

	public void finish() {
		try {
			connection.commit();
			connection.close();
		} catch (Exception e) {
			logger.error(e);
		}
		
	}

	public void clean() {
		finish();
	}
	
	public void init() {
		try {
			connection = AbstractDataConnector.getStandardConnection();
		} catch (RepositoryException e) {
			logger.error(e);
		}
	}

	public void update(Subject u) throws Exception{
		update(u.getURI(), RDF.TYPE, u.getType());
		for (Iterator<Property> it = u.getProperties().iterator();it.hasNext();) {
			Property p = it.next();
			if (p.getPredicate()!=null) {
				if (p.getType().equals(Type.LITERAL)) {
					for (Iterator<Value> itV = p.getValues().iterator();itV.hasNext();) {
						update(u.getURI(),p.getPredicate(),itV.next());
					}
				}
				else if (p.getType().equals(Type.CLASS_PROPERTY)) {
					//TODO
					logger.debug("to be implemented!!");
				}
			}
		}
		
	}

	public void loadUser(Subject sub) throws Exception{
		RepositoryResult<Statement> statements=null;
		
		try {
			statements = connection.getStatements(sub.getURI(), null, null, false);
			while (statements.hasNext()){
				Statement st = statements.next();
				Value result = st.getObject();
				URI predicate = st.getPredicate();
				if (sub.getPredicateMap().get(predicate)!=null)
					sub.getPredicateMap().get(predicate).addValue(result);
			}
			for (Iterator<Property> it = sub.getProperties().iterator();it.hasNext();) {
				Property p = it.next();
				URI u = new URIImpl(p.getNamespace()+p.getValueString());
				String date = loadSingleObject(u,Vocabulary.HASVERSIONDATETIME);
				long time =0;
				try {
					//TODO check formats
					Date d = SimpleDateFormat.getDateTimeInstance().parse(date);
					time = d.getTime();
				}
				catch (Exception e) {
					
				}
				p.setVersionDate(time);
			}
		} catch (Exception e) {
			throw e;
		}
		finally {
			if (statements!=null)
				statements.close();
		}

		
	}

	public void deleteTourism() {
		
		URI tourism = new URIImpl(Vocabulary.ONTOLOGYMODULE_NAMESPACE+"Tourism_Ontology");
		delete(tourism,true);
		tourism = new URIImpl(Vocabulary.ONTOLOGYMODULE_NAMESPACE+"Tourism_Ontology_Import");
		delete(tourism,true);
		String[] props = new String[] {
		"country",  
		"zipCode", 
		"tvRoom",  "sauna",  "heatedSwimmingpool",  "tennis",  "indoorpool",  "breakfastBuffet",  "playground",  "swimmingpool",
		"hasRoom",  "hasAccomodationType", "providesSportsProgram" ,
		"heatedSwimmingpool",  "miniBar",  "hasEventCategory",  "hasLocation",  "hasRoomType", 
		"shower" , "telephone",  "toilettes",  "bath" , "tv" , "numberOfRooms" , "miniBar" , "hasRoomType" ,
		
		"outdoorDiningArea", "numberOfMichelinStars", "wineList", "dogsAllowed", "wheelchairAccessible" ,"hasCuisine" ,
		"regionType","outdoor","addressStreet","adaptedForChildren","smokingPermission","description","billard","name","maxOccupancy","website","picture","belongsToTown","belongsToRegion",
		"regionType_","outdoor_","addressStreet_","adaptedForChildren_","smokingPermission_","description_","billard_","name_","maxOccupancy_","website_","picture_","belongsToTown_","belongsToRegion_"};
		for (int i=0;i<props.length;i++) {
			delete(new URIImpl(Vocabulary.PROPERTY_NAMESPACE+props[i]),true);
		}
	}
	

	/**
	 * @param statements
	 * @param tourism
	 */
	private void delete( URI tourism,boolean recurse) {
		RepositoryResult<Statement> statements=null;
		try {
		statements = connection.getStatements(tourism, null, null, true);
		while (statements.hasNext()){
			Statement st = statements.next();
			String result = st.getObject().stringValue();

			remove(tourism, st.getPredicate(), st.getObject());
		}
		} catch (Exception e) {
			logger.error(e);
		}
		finally {
			if (statements!=null)
				try {
					statements.close();
				} catch (RepositoryException e) {
					logger.error(e);
				}
		}
		if (!recurse)
			return;
		try {
			statements = connection.getStatements(null, null, tourism, true);
			while (statements.hasNext()){
				Statement st = statements.next();
				String result = st.getSubject().stringValue();
				delete(new URIImpl(st.getSubject().stringValue()),true);
			}
			} catch (Exception e) {
				logger.error(e);
			}
			finally {
				if (statements!=null)
					try {
						statements.close();
					} catch (RepositoryException e) {
						// TODO Auto-generated catch block
						logger.error(e);
					}
			}
	}

	public void printAllRelations(URI hasPwd) {
		RepositoryResult<Statement> statements=null;
		try {
		statements = connection.getStatements(null, hasPwd, null, true);
		while (statements.hasNext()){
			Statement st = statements.next();
			String user = st.getSubject().stringValue();
			String result = st.getObject().stringValue();
			logger.info("user: "+user+" "+result);

		}
		} catch (Exception e) {
			logger.error(e);
		}
		finally {
			if (statements!=null)
				try {
					statements.close();
				} catch (RepositoryException e) {
					logger.error(e);
				}
		}
	}

	public void update(URI uri, URI predicate, List<Value> values) throws Exception{
		connection.remove(uri, predicate,null);
		for (Iterator<Value> it = values.iterator();it.hasNext();) {
			connection.add(uri, predicate, it.next());
		}
		
	}
	
	
	
}
